package org.example.util;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import jakarta.servlet.http.HttpServletResponse;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

public class ExcelUtil {

    /**
     * 导出Excel
     */
    public static <T> void export(HttpServletResponse response, List<T> data, Class<T> clazz, String fileName) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 文件名编码（防止中文乱码）
        String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=UTF-8''" + encodedFileName + ".xlsx");

        // 写入Excel
        EasyExcel.write(response.getOutputStream(), clazz)
                .sheet("sheet1")
                .doWrite(data);
    }

    /**
     * 导入Excel（读取所有数据）
     */
    public static <T> List<T> importExcel(String filePath, Class<T> clazz) {
        return EasyExcel.read(filePath)
                .head(clazz)
                .sheet()
                .doReadSync();  // 同步读取
    }



    // 新增：将临时文件写入响应流（用于下载）
    public static void writeFileToResponse(String filePath, HttpServletResponse response) throws IOException {
        try (InputStream in = Files.newInputStream(Paths.get(filePath));
             OutputStream out = response.getOutputStream()) {
            byte[] buffer = new byte[1024 * 1024]; // 1MB缓冲区
            int len;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            out.flush();
        }
    }


    /**
     * 初始化ExcelWriter（用于分批写入）
     * @param filePath 临时文件路径
     * @param clazz 数据类型
     * @return ExcelWriter实例
     */
    public static <T> ExcelWriter initWriter(String filePath, Class<T> clazz) {
        // 确保文件父目录存在
        File file = new File(filePath);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        // 初始化写入器（指定文件路径和数据类型）
        return EasyExcel.write(filePath, clazz).build();
    }

    /**
     * 分批写入数据（控制是否写表头）
     * @param writer ExcelWriter实例
     * @param data 批次数据
     * @param isHead 是否写入表头（仅在第一页为true）
     */
    public static <T> void write(ExcelWriter writer, List<T> data, boolean isHead) {
        // 创建Sheet对象，指定sheet名称
        WriteSheet writeSheet = EasyExcel.writerSheet("用户列表")
                .head(isHead ? null : new ArrayList<>()) // 关键：isHead=false时不写表头
                .build();
        // 写入当前批次数据
        writer.write(data, writeSheet);
    }

    /**
     * 关闭写入器（释放资源）
     */
    public static void finishWriter(ExcelWriter writer) {
        if (writer != null) {
            writer.finish();
        }
    }


    /**
     * 下载服务器上的Excel文件（将临时文件写入响应流）
     * @param response 响应对象
     * @param filePath 服务器上的临时文件路径
     * @param fileName 下载时的文件名（不含后缀）
     * @throws IOException 流操作异常
     */
    public static void download(HttpServletResponse response, String filePath, String fileName) throws IOException {
        // 1. 校验文件是否存在
        File file = new File(filePath);
        if (!file.exists() || !file.isFile()) {
            throw new FileNotFoundException("导出文件不存在或已过期，请重新导出");
        }

        // 2. 设置响应头，指定文件类型和编码
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());

        // 3. 处理文件名中文乱码（兼容各浏览器）
        String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())
                .replaceAll("\\+", "%20"); // 替换空格编码
        response.setHeader("Content-Disposition",
                "attachment;filename*=UTF-8''" + encodedFileName + ".xlsx");

        // 4. 读取临时文件并写入响应流（使用NIO优化性能）
        try (InputStream in = Files.newInputStream(Paths.get(filePath));
             OutputStream out = response.getOutputStream()) {

            byte[] buffer = new byte[1024 * 1024]; // 1MB缓冲区，减少IO次数
            int len;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            out.flush(); // 确保数据全部写出
        } catch (IOException e) {
            throw new IOException("文件下载失败：" + e.getMessage(), e);
        }
    }




}